﻿using System.Xml.Serialization;

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;

using Tomahawk.Runtime.Physics;
using Tomahawk.Runtime.Physics.Interfaces;
using Tomahawk.Resources.Physics;

namespace Tomahawk.Runtime.Logic
{
    public sealed class XCollisionComponent : XComponent
    {
        #region Events

        public delegate void OnCollisionDelegate(XCollisionComponent other);
        public event OnCollisionDelegate OnCollision;

        public delegate void OnContactDelegate(XCollisionComponent other, Contact.ContactType type);
        public event OnContactDelegate OnContact;

        #endregion

        #region Public Properties
        private string descName;
        private PhysicsActorDesc actorDesc = null;
        private IPhysicsActor actor = null;

        [XmlElement("DescName")]
        public string DescName
        {
            get { return descName; }
            set { descName = value; }
        }

        [XmlIgnore]
        public PhysicsActorDesc ActorDesc
        {
            get { return actorDesc; }
        }

        [XmlIgnore]
        public IPhysicsActor Actor
        {
            get { return actor; }
        }
        #endregion

        #region Collisions

        internal void NotifyCollision(XCollisionComponent other)
        {
            if (OnCollision != null)
            {
                OnCollision(other);
            }
        }

        internal void NotifyContact(XCollisionComponent other, Contact.ContactType type)
        {
            if (OnContact != null)
            {
                OnContact(other, type);
            }
        }

        #endregion

        #region XObject

        protected override bool checkResourcesReady()
        {
            return base.checkResourcesReady() && actor.IsReady;
        }

        protected override void OnUpdate(float elapsedTime)
        {
            base.OnUpdate(elapsedTime);
        }

        protected override void OnPreBeginPlay()
        {
            base.OnPreBeginPlay();

            if (actor != null)
            {
                PhysicsManager physicsManager = Engine.Instance.PhysicsManager;
                actor.MoveTo("root", Owner.SceneComponent.SceneNode.Position, Owner.SceneComponent.SceneNode.Rotation);
                physicsManager.Link(this, actor);
            }
        }

        protected override void OnPostBeginPlay()
        {
            base.OnPostBeginPlay();
        }

        protected override void OnInitialize()
        {
            base.OnInitialize();

            PhysicsManager physicsManager = Engine.Instance.PhysicsManager;
            if (!physicsManager.Scene.CreateActor(descName, out actor))
            {
                //@TODO [CLOPEZ]: Error handling
            }
        }

        public override void OnBeforeDestroy() 
        {
            if (actor != null)
            {
                PhysicsManager physicsManager = Engine.Instance.PhysicsManager;
                physicsManager.Scene.DestroyActor(actor);
                physicsManager.Unlink(this);
                actor = null;
            }
            base.OnBeforeDestroy();
        }

        public override void OnAfterDestroy() 
        {
            base.OnAfterDestroy();
        }

        #endregion
    }
}
